/*
    krpanoJS javascript tags functionality
*/

var krpanoplugin = function()
{
    var local = this;   // save the 'this' pointer from the current plugin object

    var krpano = null;  // the krpano and plugin interface objects
    var plugin = null;
    var domains = new Array(
        "in3sixty.com",
        "stadiums.in3sixty.com",
        "gigapixelfancam.com",
        "fancam.com",
        "fans.in3sixty.com",
        "localhost"
    );

    var plugincanvas = null;        // optionally - a canvas object for graphic content
    var plugincanvascontext = null;


    // registerplugin - startup point for the plugin (required)
    // - krpanointerface = krpano interface object
    // - pluginpath = string with the krpano path of the plugin (e.g. "plugin[pluginname]")
    // - pluginobject = the plugin object itself (the same as: pluginobject = krpano.get(pluginpath) )
    local.registerplugin = function(krpanointerface, pluginpath, pluginobject)
    {
        krpano = krpanointerface;
        plugin = pluginobject;

        var domain = "in3sixty.com";     // TODO here, need to add extra security
        if( true/*isDomainAllowed(domain, domains )*/ )
        {
            initplugin();
        }
        else{
            krpano.call("showlog(true);");
            krpano.set("debugmode", true);
            var domain = domain;
            debug("[" + plugin.name + "] - " + domain + " not allowed");
        }


    }

    // unloadplugin - end point for the plugin (optionally)
    // - will be called from krpano when the plugin will be removed
    // - everything that was added by the plugin (objects,intervals,...) should be removed here
    local.unloadplugin = function()
    {
        plugin = null;
        krpano = null;
    }

    // hittest - ngrunning for clicks on the plugin (optionally)
    // - when the plugin has a graphical irregular shape then it's possible to check here for mouse clicks on it
    // - the typical usage is to check for a hit on the canvas element
    local.hittest = function(x,y)
    {
        if (plugincanvascontext)
        {
            return plugincanvascontext.isPointInPath(x,y);
        }

        return false;
    }

    // onresize - the plugin was resized from xml krpano (optionally)
    // - width,height = the new size for the plugin
    // - when not defined then only the parent html element will be scaled
    local.onresize = function(width,height)
    {
        // not used in this example

        return false;
    }


    /*
     *
     *  plugin functions:
     *
     */
    function isDomainAllowed(domain, allowedArray )
    {

        for( var i = 0; i < allowed.length; ++i )
        {
            if( domain == allowed[i] )
            {
                return true;
            }
        }
        for( var j = 0; j < allowed.length; ++j )
        {
            if( domain.substr( - ( allowed[j].length + 1 ) ) == "." + allowed[j] )
            {
                return true;
            }
        }

        return true;
    }


    function debug(str)
    {
        if(plugin.debug == "true"){
            krpano.call("showlog(true);");
            krpano.set("debugmode", true);
            krpano.trace(0,str);
        }
    }


    function print(str)
    {
        krpano.call("showlog(true);");
        krpano.set("debugmode", true);
        krpano.trace(0,str);
    }


    /*
     * Private variables
     */

    var objTagStageValues = new Object();
    var objTagDefaults = new Object();
    var objTagPoints = new Object();
    var objTagStagePoints = new Array();
    var objLastTagReq = new Object();
    var boolGetTags_timeout = new Boolean(false);
    var boolShowTagsOnLoad = new Boolean(true);
    var boolPauseLoading = false;


    /*
     * Main initialisation of the plugin
     */
    function initplugin()
    {
        debug("plugin[" + plugin.name + "] - initplugin called");
        var no_errors = true;
        if(plugin.tagpointsurl == undefined){
            no_errors = false;
            debug("plugin[" + plugin.name + "] - Missing 'tagpointsurl' parameter");
        }

        if(plugin.tagdefaultsurl == undefined){
            no_errors = false;
            debug("plugin[" + plugin.name + "] - Missing 'tagdefaultsurl' parameter");
        }

        if(no_errors){

            plugin.hidetags = hidetags;
            plugin.showtags = showtags;
            plugin.gettags = gettags;

            plugin.start = start;

            plugin.removetag = removetag;

            plugin.restart = restart;

            plugin.removebyname = removebyname;

            plugin.pause = pause;

            plugin.resume = resume;

            if(plugin.sensitivity == undefined){
                plugin.sensitivity = 5;
            }

            if(plugin.req_period == undefined){
                plugin.req_period = 3000;
            }

            if(plugin.autostart == undefined){
                plugin.autostart = "true";
            }

            if(plugin.persistent == undefined){
                plugin.persistent = "false";
            }

            if(plugin.runonce == undefined){
                plugin.runonce = "false";

            }

            plugin.set_sensitivity = set_sensitivity;
            if(plugin.autostart == "true"){
                start();
            }
            else{
                get_tagdefaults();
                set_sensitivity();
            }
        }
    }


    /*
     * the default values for all tags
     */
    function get_tagdefaults()
    {

        var tagrequest =  new XMLHttpRequest ();
        tagrequest.contentType = "application/json";
        tagrequest.onreadystatechange =   get_tagdefaults_req_handler;
        var url = krpano.parsePath(plugin.tagdefaultsurl);

        tagrequest.open("GET",url,true);
        debug("plugin[" + plugin.name + "] - get_tagdefaults.send  GET: "+ url);

        tagrequest.send ();
    }


    function get_tagdefaults_req_handler() {

       // debug("plugin[" + plugin.name + "] - get_tags: req_handler status:" + this.status+ "readyState: "+this.readyState);

        if(this.readyState == 4) {
            if(this.status == 200){

                //debug("plugin[" + plugin.name + "] - get_tagdefaults: req_handler :response:" + this.responseText);

                objTagDefaults = JSONa.decode(this.responseText);


                debug("plugin[" + plugin.name + "] - get_tagsdefaults: req_handler obj:" +objTagDefaults["url"]);


            }
            else{
                // TODO error cases
            }
        }
    }

    function set_tagdefault(prop, value){
        objTagDefaults[prop] = value;
    }



    function hidetags()
    {
        debug("plugin[" + plugin.name + "] - hidetags called");

        var strPanoCall = new String("");

        set_tagdefault("alpha", "0");
        set_tagdefault("enabled", "false");
        boolShowTagsOnLoad = false;
        pause();

        for (var tag in objTagStagePoints){
            strPanoCall += "tween(hotspot[" + objTagStagePoints[tag].name + "].alpha, 0 ,1, default, set(hotspot[" + objTagStagePoints[tag].name + "].enabled, false));";
        }

        debug (strPanoCall);
        krpano.call(strPanoCall);
     }

    function showtags()
    {
        debug("plugin[" + plugin.name + "] - showtags called");

        var strPanoCall = new String("");

        set_tagdefault("alpha", "0");
        set_tagdefault("enabled", "true");
        boolShowTagsOnLoad = true;
        resume();

        for (var tag in objTagStagePoints){
            strPanoCall += "set(hotspot[" + objTagStagePoints[tag].name + "].enabled, true);";
            strPanoCall += "tween(hotspot[" + objTagStagePoints[tag].name + "].alpha, 1 ,1);";
        }

        krpano.call(strPanoCall);
        debug(strPanoCall);
     }


    function gettags(onloaded)
    {

        //console.log("gettags: called.....");
        debug("plugin[" + plugin.name + "] - gettags called, onloaded:"+onloaded);
        get_tags(onloaded);
    }


    function start()
    {
        debug("plugin[" + plugin.name + "] - start called");
        krpano.set("events.onnewpano", startplugin());
    }

    function startplugin()
    {
        debug("plugin[" + plugin.name + "] - startplugin called");

        get_tagdefaults();
        set_sensitivity();

        if(plugin.runonce == "false"){

             krpano.set("events.onviewchange", sensitivity);

             // timeGetTags_timer.addEventListener(TimerEvent.TIMER, set_boolGetTags_timeout);
             //timeGetTags_timer.start();
        }
        else{
			gettags();
             krpano.set("events.onloadcomplete", gettags);
        }

    }

    function restart()
    {
        debug("plugin[" + plugin.name + "] - restart called");
        var objTagStagePointsFiltered = new Array();

        for (var tag in objTagStagePoints){
            krpano.call("removehotspot(" + objTagStagePoints[tag].name + ")");
        }

        objTagStagePoints = objTagStagePointsFiltered;
        objTagStagePointsFiltered = null;

        get_tags();
    }


    function removebyname(strName)
    {
        debug("plugin[" + plugin.name + "] - removebyname called");

        var objTagStagePointsFiltered = new Array();
        for (var tag in objTagStagePoints){
            if(strName != objTagStagePoints[tag].name){
                 objTagStagePointsFiltered.push(objTagStagePoints[tag]);
            }
            else{
                 krpano.call("removehotspot(" + objTagStagePoints[tag].name + ")");
            }
        }

        objTagStagePoints = objTagStagePointsFiltered;
        objTagStagePointsFiltered = null;
    }

    function pause()
    {
        debug("plugin[" + plugin.name + "] - pause called");
        boolPauseLoading = true;
    }

    function resume()
    {
        debug("plugin[" + plugin.name + "] - resume called");
        boolPauseLoading = false;
    }

    function set_sensitivity()
    {
        objLastTagReq.sensitivity = plugin.sensitivity;
        var view = krpano.get("view");

        objLastTagReq.atv = view.vlookat;
        objLastTagReq.ath = view.hlookat;
        objLastTagReq.fov = view.fov;
        objLastTagReq.fovfactor = 0;
        objLastTagReq.time = 0;


        debug ("plugin[" + plugin.name + "] - set_sensitivity: ath"+objLastTagReq.atv + " atv:"+objLastTagReq.ath + " fov:"+ objLastTagReq.fov);
    }


    function sensitivity()
    {
        //debug("plugin[" + plugin.name + "] - sensitivity called" + new Date().getTime() + " objLastTagReq "+  objLastTagReq.time + " limit"+ plugin.req_period);

        var timeNow = new Date().getTime();
        if (timeNow < objLastTagReq.time + plugin.req_period){
            return;
        }

        var fovfactor;
        var factor = 10 * (objLastTagReq.sensitivity / 5);

        if(krpano.view.fov >= 120){
            fovfactor = 1.5;
        }else if(krpano.view.fov >= 90){
            fovfactor = 1.3;
        }else if(krpano.view.fov >= 60){
            fovfactor = 1.1;
        }else if(krpano.view.fov >= 30){
            fovfactor = 0.9;
        }else if(krpano.view.fov >= 20){
            fovfactor = 0.9;
        }else if(krpano.view.fov >= 10){
            fovfactor = 0.7;
        }else if(krpano.view.fov >= 5){
            fovfactor = 0.5;
        }else if(krpano.view.fov < 5){
            fovfactor = 0.3;
        }

        //debug("plugin[" + plugin.name + "] - sensitivity: fovFactor"+fovfactor);

        var atvdiff = objLastTagReq.atv - krpano.view.vlookat;
        if(atvdiff < 0){
            atvdiff = atvdiff * -1;
        }

        var athdiff = objLastTagReq.ath - krpano.view.hlookat;
        if(athdiff < 0){
            athdiff = athdiff * -1;
        }

        //debug("plugin[" + plugin.name + "] - sensitivity: fovFactor:"+fovfactor+" athdiff:"+athdiff+" atvdiff:"+atvdiff+" (factor * fovfactor):"+(factor * fovfactor));

        if((atvdiff > (factor * fovfactor) || athdiff > (factor * fovfactor) || fovfactor != objLastTagReq.fovfactor) /*&& boolGetTags_timeout */&& boolPauseLoading === false)
        {
            //timeGetTags_timer.addEventListener(TimerEvent.TIMER, set_boolGetTags_timeout);
            //timeGetTags_timer.start();

            boolGetTags_timeout = false;

            objLastTagReq.atv = krpano.view.vlookat;
            objLastTagReq.ath = krpano.view.hlookat;
            objLastTagReq.fovfactor = fovfactor;
            objLastTagReq.time = new Date().getTime();

            get_tags();
        }
    }


    function get_tags(onloadedaction)
    {
        //debug("plugin[" + plugin.name + "] - get_tags called");

        calc_visible_stage();

        var tagrequest =  new XMLHttpRequest ();
        tagrequest.contentType = "application/json";
        var url = krpano.parsePath(plugin.tagpointsurl);

        var index = plugin.tagpointsurl.indexOf("?");
        if(index == -1){
            url += '?';
        }else{
            url += '&';
        }

        // var foc_range_str = 'fov_min=' + fov_min + '&' + 'fov_max=' + fov_max;
        url += "fov=" + objTagStageValues.fov + '&' + 'atv_min=' + objTagStageValues.atv_min + '&' + 'ath_min=' + objTagStageValues.ath_min + '&' + 'atv_max=' + objTagStageValues.atv_max + '&' + 'ath_max=' + objTagStageValues.ath_max;
        tagrequest.onreadystatechange =  function (){

            //debug("plugin[" + plugin.name + "] - get_tags: req_handler status:" + this.status+ "readyState: "+this.readyState);

            if(this.readyState == 4) {
                if(this.status == 200){
                    decode_tagpointsurl(this);

                    if (typeof onloadedaction != 'undefined'){
                        krpano.call(onloadedaction);
                    }
                }
                else{
                    debug("plugin[" + plugin.name + "] - get_tags: req_handler: error code:"+this.status);
                }
            }
        };

        tagrequest.open("GET",url,true);
        //debug("plugin[" + plugin.name + "] - get_tags: tagrequest.send ()");

        tagrequest.send ();

    }

    function decode_tagpointsurl(req) {

        debug("plugin[" + plugin.name + "] - decode_tagpointsurl: "+req.responseText);

         objTagPoints = JSONa.decode(req.responseText);

        if(plugin.persistent == "false"){
             remove_tags();
        }

        for (var tag in objTagPoints){
           create_tag(objTagPoints[tag]);
        }

        objTagPoints = null;
    }


    function removetag(name){

        debug("removetag:" + name);
        if (plugin.persistent != "false"){
            name = "pers_"+name;
        }

        for (var tag in objTagStagePoints){
            if (objTagStagePoints[tag].name == name){

                // notify that we are removing
                if ( plugin.ontagremove !== undefined){

                    var actioncall = plugin.ontagremove.replace("{name}", objTagStagePoints[tag].name );
                    krpano.call(actioncall);
                }

                //debug("NOW removing the hotspot"+ objTagStagePoints[tag].name );
                //krpano.call("removehotspot(" + objTagStagePoints[tag].name + ");");

                debug("[" + plugin.name + "] - remove " + objTagStagePoints[tag].name + "");
                krpano.call("removehotspot(" + objTagStagePoints[tag].name + ");");
                delete objTagStagePoints[tag];
            }
        }
    }


    function remove_tags()
    {
        //debug("plugin[" + plugin.name + "] - remove_tags:");

        var objTagStagePointsFiltered = new Array();
        for (var tag in objTagStagePoints){
            var onstage_atv = false;
            var onstage_ath = false;

            /*******/
            /* ATV */
            /*******/
            if(objTagStageValues.atv_min < objTagStageValues.atv_max){
                if((objTagStagePoints[tag].atv > objTagStageValues.atv_min) && (objTagStagePoints[tag].atv < objTagStageValues.atv_max)){
                    onstage_atv = true;
                }
            }

            if(objTagStageValues.atv_min > objTagStageValues.atv_max){
                if((objTagStagePoints[tag].atv > objTagStageValues.atv_min) || (objTagStagePoints[tag].atv < objTagStageValues.atv_max)){
                    onstage_atv = true;
                }
            }

            /*******/
            /* ATH */
            /*******/
            if(objTagStageValues.ath_min < objTagStageValues.ath_max){
                if((objTagStagePoints[tag].ath > objTagStageValues.ath_min) && (objTagStagePoints[tag].ath < objTagStageValues.ath_max)){
                    onstage_ath = true;
                }
            }

            if(objTagStageValues.ath_min > objTagStageValues.ath_max){
                if((objTagStagePoints[tag].ath > objTagStageValues.ath_min) || (objTagStagePoints[tag].ath < objTagStageValues.ath_max)){
                    onstage_ath = true;
                }
            }

            if(onstage_atv && onstage_ath){
                objTagStagePointsFiltered.push(objTagStagePoints[tag]);
                debug("[" + plugin.name + "] - Did not remove " + objTagStagePoints[tag].name + " - Still on stage");
            }else{
                debug("[" + plugin.name + "] - remove " + objTagStagePoints[tag].name + " - Not on Stage");

                // notify that we are removing
                if ( plugin.ontagremove !== undefined){

                    var actioncall = plugin.ontagremove.replace("{name}", objTagStagePoints[tag].name );
                    krpano.call(actioncall);
                }

                krpano.call("removehotspot(" + objTagStagePoints[tag].name + ");");
            }
        }

        //krpano.call("js(console.log("+JSONa.encode(objTagStagePoints)+"))");

        objTagStagePoints = objTagStagePointsFiltered;
        objTagStagePointsFiltered = null;
    }


    function create_tag(objTag)
    {
        //debug("plugin[" + plugin.name + "] - create_tag:" );

        var strCreateTagCall = new String("");
        var objTagBase = new Object();
        var tagIsOnStage = new Boolean(false);

        for (var val0 in objTagDefaults){
            objTagBase[val0] = objTagDefaults[val0];
        }

        for (var val1 in objTag){
            objTagBase[val1] = objTag[val1];
        }

        if(objTagBase.name == undefined){
            objTagBase.name = "tag_" + Math.floor(Math.random() * 1000000) + "_" + Math.floor(Math.random() * 1000000);
        }

        for (var tag in objTagStagePoints){
            if(objTagStagePoints[tag].name == objTagBase.name){
                tagIsOnStage = true;
            }
        }

        if(tagIsOnStage == false){
            objTagStagePoints.push(objTagBase);
            strCreateTagCall += 'removehotspot(' + objTagBase.name + '); addhotspot(' + objTagBase.name + ');';
        }

        for (var val2 in objTagBase){

            if(val2 == 'alpha' && boolShowTagsOnLoad == true){
                if(tagIsOnStage == false){
                    strCreateTagCall += 'set(hotspot[' + objTagBase.name + '].alpha, 0);';
                }else{
                    strCreateTagCall += 'set(hotspot[' + objTagBase.name + '].alpha, 1);';
                }
            }
            else if (val2 == 'fov'){
                strCreateTagCall += 'set(hotspot[' + objTagBase.name + '].scale,'+ objTagBase[val2]/90.0+');';
            }
            else{
                strCreateTagCall += 'set(hotspot[' + objTagBase.name + '].' + val2 + ', ' + objTagBase[val2] + ');';
            }
        }

        if(boolShowTagsOnLoad == true && tagIsOnStage == false){
            strCreateTagCall += "tween(hotspot[" + objTagBase.name + "].alpha, 1 ,1);";
        }

        //debug(strCreateTagCall);
        krpano.call(strCreateTagCall);

        strCreateTagCall = null;
    }


    function signed_h(ath){
        h = ath%360; /* restrict to +-360 */
        if (h<=-180){
            h = 360+h;
        }
        else if(h>180){
            h = 360-h;
        }
        return h;
    }

    function calc_visible_stage()
    {
        //debug("plugin[" + plugin.name + "] - calc_visible_stage called");

        objTagStageValues.width = 0;
        objTagStageValues.width_middle = 0;
        objTagStageValues.height = 0;
        objTagStageValues.height_middle = 0;
        objTagStageValues.atv_min = 0;
        objTagStageValues.ath_min = 0;
        objTagStageValues.atv_max = 0;
        objTagStageValues.ath_max = 0;
        objTagStageValues.fov = 0;

        objTagStageValues.fov = krpano.view.fov;

        objTagStageValues.width = krpano.get("stagewidth");
        objTagStageValues.width_middle = parseInt(objTagStageValues.width) / 2;
        krpano.set("width_middle", objTagStageValues.width_middle);

        objTagStageValues.height = krpano.get("stageheight");
        objTagStageValues.height_middle = parseInt(objTagStageValues.height) / 2;
        krpano.set("height_middle", objTagStageValues.height_middle);

        krpano.call(String("screentosphere(0,height_middle,fc_ath_min,dummy);"));
        objTagStageValues.ath_min = krpano.get('fc_ath_min');

        krpano.call(String("screentosphere(stagewidth,height_middle,fc_ath_max,dummy);"));
        objTagStageValues.ath_max = krpano.get("fc_ath_max");

        krpano.call(String("screentosphere(width_middle,0,dummy,fc_atv_min);"));
        objTagStageValues.atv_min = krpano.get('fc_atv_min');

        krpano.call(String("screentosphere(width_middle,stageheight,dummy,fc_atv_max);"));
        objTagStageValues.atv_max = krpano.get("fc_atv_max");

        /*console.log(" ath_min:"+objTagStageValues.ath_min +
                    ", ath_max:"+ objTagStageValues.ath_max +
                    ", atv_min:"+objTagStageValues.atv_min +
                    ", atv_max"+objTagStageValues.atv_max +
                    ", fov:"+ objTagStageValues.fov +
                    ", width:"+ objTagStageValues.width +
                    ", height:"+ objTagStageValues.height +
                    ", view.hlookat:"+ signed_h(krpano.view.hlookat) +
                    ", view.vlookat:"+ krpano.view.vlookat +
                    ", stagewidth:"+ krpano.get("stagewidth") +
                    ", stageheight:" + krpano.get("stageheight"));*/


        // workaround for krpano bug showing wrong athmin and athmax for small values

        // adjust to +-180;
        fc_hlookat = signed_h(krpano.view.hlookat);

        // calculation bug in screentosphere krpano

        if (objTagStageValues.ath_min < objTagStageValues.ath_max){
            if (objTagStageValues.ath_min>fc_hlookat){
                console.log("ath_min > hlookat, ath_min="+objTagStageValues.ath_min+
                            " hlookat="+ fc_hlookat +" defaulting to fov/2="+ String(fc_hlookat - krpano.view.fov/2));
                objTagStageValues.ath_min = signed_h(fc_hlookat - krpano.view.fov/2);
            }
            if (objTagStageValues.ath_max<fc_hlookat){
                console.log("ath_max < hlookat, ath_max="+objTagStageValues.ath_max+
                            " hlookat="+ fc_hlookat +" defaulting to fov/2="+ String(fc_hlookat + krpano.view.fov/2));
                objTagStageValues.ath_max = signed_h(krpano.view.hlookat + krpano.view.fov/2);
            }
        }else{

            if (objTagStageValues.ath_min<fc_hlookat){
                console.log("ath_min < hlookat, ath_min="+objTagStageValues.ath_min+
                            " hlookat="+ fc_hlookat +" defaulting to fov/2="+ String(fc_hlookat - krpano.view.fov/2));
                objTagStageValues.ath_min = signed_h(fc_hlookat - krpano.view.fov/2);
            }
            if (objTagStageValues.ath_max>fc_hlookat){
                console.log("ath_max > hlookat, ath_max="+objTagStageValues.ath_max+
                            " hlookat="+ fc_hlookat +" defaulting to fov/2="+ String(fc_hlookat + krpano.view.fov/2));
                objTagStageValues.ath_max = signed_h(krpano.view.hlookat + krpano.view.fov/2);
            }
        }


        /* -90 <=> 90 */
        if (objTagStageValues.atv_min>krpano.view.vlookat){
              console.log("atv_min > vlookat, atv_min="+objTagStageValues.atv_min+
                          " vlookat="+ krpano.view.vlookat +" defaulting to fov/2="+ String(krpano.view.vlookat - krpano.view.fov/2));
                objTagStageValues.atv_min = krpano.view.vlookat - krpano.view.fov/2;
        }
        if (objTagStageValues.atv_max<krpano.view.vlookat){
            console.log("atv_max > vlookat, atv_max="+objTagStageValues.atv_max+
                        " vlookat="+ krpano.view.vlookat +" defaulting to fov/2="+ String(krpano.view.vlookat + krpano.view.fov/2));
            objTagStageValues.atv_max = krpano.view.vlookat + krpano.view.fov/2;
        }

    }

};